﻿using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using Devonline.AuxiliaryTools.DatabaseTools;
using Devonline.Database.PostgreSQL;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using PluralizeService.Core;

namespace Devonline.Identity.Admin.Controllers;

/// <summary>
/// 系统初始化控制器
/// </summary>
#if DEBUG
[AllowAnonymous]
#else
[Authorize(Roles = GROUP_MAINTAINERS)]
#endif
[ApiController]
[Route("api/[controller]")]
[Description("初始化")]
[AccessAuthorize(Code = "AS0XInitial", ResourceType = ResourceType.Service, Roles = GROUP_MAINTAINERS)]
public class InitialController(
    ILogger<InitialController> logger,
    IDataService<Parameter> parameterService,
    AdminSetting appSetting,
    UserManager<User> userManager,
    RoleManager<Role> roleManager,
    SignInManager<User> signInManager,
    IdentityDbContext context,
    AuthorizationService authorizationService,
    IDataService<User> userService,
    IDataService<Role> roleService,
    IDataService<Resource> resourceService,
    IDataService<AccessRule> accessRuleService,
    IServiceProvider serviceProvider) :
    ControllerBase
{
    private readonly ILogger<InitialController> _logger = logger;
    private readonly IDataService<Parameter> _parameterService = parameterService;
    private readonly AdminSetting _appSetting = appSetting;
    private readonly UserManager<User> _userManager = userManager;
    private readonly RoleManager<Role> _roleManager = roleManager;
    private readonly SignInManager<User> _signInManager = signInManager;
    private readonly IdentityDbContext _context = context;
    private readonly AuthorizationService _authorizationService = authorizationService;
    private readonly IDataService<User> _userService = userService;
    private readonly IDataService<Role> _roleService = roleService;
    private readonly IDataService<Resource> _resourceService = resourceService;
    private readonly IDataService<AccessRule> _accessRuleService = accessRuleService;
    private readonly IServiceProvider _serviceProvider = serviceProvider;

    [AllowAnonymous]
    [HttpGet("InitSystem")]
    [Display(Name = "初始化系统")]
    [AccessAuthorize(Code = "AS0XInitialIInitSystem")]
    public async Task<IActionResult> InitSystemAsync()
    {
        _logger.LogInformation("系统初始化!");

        await AutoMigrationAsync();
        await InitAccountAsync();
        await InitAccessAuthorizesAsync();
        await InitParameter();

        _logger.LogInformation("系统初始化完成!");
        return Ok();
    }

    [HttpGet("AutoMigration")]
    [Display(Name = "数据迁移")]
    [AccessAuthorize(Code = "AS0XInitialIAutoMigration")]
    public async Task<IActionResult> AutoMigrationAsync()
    {
        await _context.AutoMigrationAsync();
        _logger.LogInformation("数据迁移完成!");
        return Ok();
    }

    [HttpGet("InitAccount")]
    [Display(Name = "初始化账户")]
    [AccessAuthorize(Code = "AS0XInitialIInitAccount")]
    public async Task<IActionResult> InitAccountAsync()
    {
        _logger.LogInformation("初始化账户开始!");

        #region 创建内置角色
        await _context.Users.ExecuteDeleteAsync();
        await _context.Roles.ExecuteDeleteAsync();
        await _context.UserRoles.ExecuteDeleteAsync();
        await _context.UserClaims.ExecuteDeleteAsync();

        var authTypes = Enum.GetValues<AuthorizeType>();
        foreach (var authType in authTypes)
        {
            var roleName = authType.ToString().ToCamelCase();
            roleName = PluralizationProvider.Pluralize(roleName);
            var displayName = authType.GetDisplayName();
            var role = new Role
            {
                Id = authType.ToString("D"),
                Name = roleName,
                Alias = displayName,
                Type = authType,
                Description = displayName,
                CreatedBy = USER_SYSTEM,
                UpdatedBy = USER_SYSTEM
            };

            _roleService.Create(role);
            _roleService.Update(role);
            await _roleManager.CreateAsync(role);
        }
        #endregion

        #region 创建内置用户, 并给内置用户分配角色
        ArgumentException.ThrowIfNullOrWhiteSpace(_appSetting.DefaultPassword);

        //默认超管
        var user = new User
        {
            Id = AuthorizeType.Administrator.ToString("D"),
            Name = "超级管理员",
            UserName = USER_ADMINISTRATOR,
            Alias = "超级管理员",
            Type = AuthorizeType.Administrator,
            Description = "超级管理员",
            CreatedBy = USER_SYSTEM,
            UpdatedBy = USER_SYSTEM
        };

        _userService.Create(user);
        _userService.Update(user);
        await _userManager.CreateAsync(user);
        await _userManager.AddPasswordAsync(user, _appSetting.DefaultPassword);
        await _userManager.AddToRoleAsync(user, GROUP_ADMINISTRATOR);
        await _userManager.InitUserClaimsAsync(user);

        //默认开发者
        user = new User
        {
            Id = AuthorizeType.Developer.ToString("D"),
            Name = "开发者",
            UserName = USER_DEVELOPER,
            Alias = "开发者",
            Type = AuthorizeType.Developer,
            Description = "系统开发者"
        };

        _userService.Create(user);
        _userService.Update(user);
        await _userManager.CreateAsync(user);
        await _userManager.AddPasswordAsync(user, _appSetting.DefaultPassword);
        await _userManager.AddToRoleAsync(user, GROUP_DEVELOPER);
        await _userManager.InitUserClaimsAsync(user);

        //系统本身
        user = new User
        {
            Id = AuthorizeType.System.ToString("D"),
            Name = "系统",
            UserName = USER_SYSTEM,
            Alias = "系统",
            Type = AuthorizeType.System,
            Description = "系统本身"
        };

        _userService.Create(user);
        _userService.Update(user);
        await _userManager.CreateAsync(user);
        await _userManager.AddToRoleAsync(user, GROUP_SYSTEM);
        await _userManager.InitUserClaimsAsync(user);

        //匿名用户
        user = new User
        {
            Id = AuthorizeType.Anonymous.ToString("D"),
            Name = "匿名用户",
            UserName = USER_ANONYMOUS,
            Alias = "匿名用户",
            Type = AuthorizeType.Anonymous,
            Description = "匿名用户"
        };

        _userService.Create(user);
        _userService.Update(user);
        await _userManager.CreateAsync(user);
        await _userManager.AddToRoleAsync(user, GROUP_ANONYMOUS);
        await _userManager.InitUserClaimsAsync(user);
        #endregion

        _logger.LogInformation("初始化账户完成!");
        return Ok();
    }

    [HttpGet("InitAccessAuthorizes")]
    [Display(Name = "初始化访问授权")]
    [AccessAuthorize(Code = "AS0XInitialIInitAccessAuthorizes")]
    public async Task<IActionResult> InitAccessAuthorizesAsync()
    {
        _logger.LogInformation("认证系统初始化访问授权开始!");
        await _authorizationService.InitialAccessAuthorizesAsync(Assembly.GetExecutingAssembly(), new Resource { Code = "AS0", Content = _appSetting.Copyright!, Name = _appSetting.Name });
        _logger.LogInformation("认证系统初始化访问授权完成!");
        return Ok();
    }

    /// <summary>
    /// 初始化基础数据
    /// </summary>
    /// <returns></returns>
    [HttpGet("InitParameter")]
    [DisplayName("初始化基础数据")]
    [AccessAuthorize(Code = "AS0XInitialIInitParameter")]
    public async Task<IActionResult> InitParameter()
    {
        var parameter = await _parameterService.GetQueryable().FirstOrDefaultAsync(x => x.Key == "root");
        if (parameter != null)
        {
            return Ok("基础数据已经初始化过了!");
        }

        parameter = new Parameter
        {
            Id = "0",
            Index = 0,
            Key = "root",
            Value = "Root",
            Text = "基础数据根节点"
        };
        parameter.Create();
        var list = new List<Parameter> { parameter };
        var types = typeof(AppSetting).Assembly.GetTypes().Where(x => x.IsEnum);
        if (types.Any())
        {
            var index = 101;
            var extensionType = typeof(AspNetCoreExtensions);
            var toLowerTypes = new string[] { nameof(DatabaseType), nameof(EncryptionAlgorithm), nameof(HashAlgorithm), nameof(SymmetricAlgorithm), nameof(Currency) };
            var boolTypes = new string[] { nameof(YesOrNo), nameof(HaveOrNot), nameof(AgreeOrNot) };
            foreach (var type in types.Where(x => !boolTypes.Contains(x.Name)))
            {
                var parameters = extensionType.InvokeGenericMethod<List<Parameter>>(nameof(AspNetCoreExtensions.GetParametersFromEnum), index++, [toLowerTypes.Contains(type.Name)], type);
                if (parameters is not null && parameters.Count != 0)
                {
                    list.AddRange(parameters);
                }
            }

            index = 201;
            foreach (var type in types.Where(x => boolTypes.Contains(x.Name)))
            {
                var parameters = extensionType.InvokeGenericMethod<List<Parameter>>(nameof(AspNetCoreExtensions.GetBoolParametersFromEnum), index++, [toLowerTypes.Contains(type.Name)], type);
                if (parameters is not null && parameters.Count != 0)
                {
                    list.AddRange(parameters);
                }
            }
        }

        list.Add(new Parameter
        {
            ParentId = "0",
            Id = "999",
            Index = 999,
            Key = "special",
            Value = "Special",
            Text = "特殊配置项"
        });
        list.Add(new Parameter
        {
            ParentId = "999",
            Id = "999999",
            Index = 999999,
            Key = PARAMETER_ALLOWEDIPADDRESSES,
            Value = "::1;127.0.0.1",
            Text = "允许访问的 IP 地址"
        });

        await _parameterService.AddsAsync(list);
        return Ok("基础数据初始化完成!");
    }

    /// <summary>
    /// 允许一个IP地址访问
    /// </summary>
    /// <returns></returns>
    [HttpGet("AllowIpAddress")]
    [DisplayName("允许一个IP地址访问")]
    [AccessAuthorize(Code = "AS0XInitialIAllowIpAddress")]
    public async Task<IActionResult> AllowIpAddressAsync(string ipAddress)
    {
        var parameter = await _parameterService.FirstOrDefaultAsync(x => x.Key == PARAMETER_ALLOWEDIPADDRESSES);
        if (parameter is null)
        {
            return NotFound();
        }

        var ipAddresses = parameter.Value.Split(CHAR_SEMICOLON, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToList();
        if (ipAddresses is not null && ipAddresses.Count != 0 && !ipAddresses.Contains(ipAddress))
        {
            ipAddresses.Add(ipAddress);
            parameter.Value = ipAddresses.ToString<string>(DEFAULT_SECTION_STRING);
            await _parameterService.UpdateAsync(parameter);
            await _parameterService.RemoveCacheAsync(CACHE_APPLICATION_ALLOWEDIPADDRESSES);
            _logger.LogInformation($"已添加一个IP地址: {ipAddress} 的可访问权限");
        }

        return Ok();
    }
    /// <summary>
    /// 移除一个缓存
    /// </summary>
    /// <returns></returns>
    [HttpGet("RemoveCache/{key}")]
    [DisplayName("移除缓存")]
    [AccessAuthorize(Code = "AS0XInitialIRemoveCache")]
    public async Task<IActionResult> RemoveCacheAsync(string key)
    {
        await _parameterService.RemoveCacheAsync(key);
        _logger.LogInformation($"已移除缓存: {key}");
        return Ok();
    }

    /// <summary>
    /// 拦截器测试
    /// </summary>
    /// <returns></returns>
    [HttpGet("Intercept")]
    [DisplayName("拦截器测试")]
    [AccessAuthorize(Code = "AS0XInitialIIntercept")]
    public async Task<IActionResult> InterceptAsync()
    {
        _logger.LogInformation("拦截开始!");
        var _httpInterceptor = _serviceProvider.GetRequiredService<HttpInterceptor>();
        _httpInterceptor.Activate();
        Thread.Sleep(UNIT_SECONDS_A_MINUTE * UNIT_THOUSAND);
        _httpInterceptor.Done();
        _logger.LogInformation("拦截完成!");
        await Task.CompletedTask;
        return Ok();
    }
    /// <summary>
    /// 业务拦截器测试
    /// </summary>
    /// <returns></returns>
    [HttpGet("InterceptBusiness/{key}/{docs}")]
    [DisplayName("拦截器测试")]
    [AccessAuthorize(Code = "AS0XInitialIInterceptBusiness")]
    public async Task<IActionResult> InterceptBusinessAsync(string key, string docs)
    {
        _logger.LogInformation($"{key} 拦截开始!");
        var _httpInterceptor = _serviceProvider.GetRequiredService<HttpInterceptor>();
        _httpInterceptor.Activate(key, docs);
        Thread.Sleep(UNIT_SECONDS_A_MINUTE * UNIT_THOUSAND);
        _httpInterceptor.Done(key);
        _logger.LogInformation($"{key} 拦截完成!");
        await Task.CompletedTask;
        return Ok();
    }

    /// <summary>
    /// 数据库移植
    /// </summary>
    /// <returns></returns>
    [HttpGet("DataMigration")]
    [DisplayName("数据库移植")]
    [AccessAuthorize(Code = "AS0XInitialIDataMigration")]
    public async Task DataMigrationAsync()
    {
        var databaseService = _serviceProvider.GetRequiredService<DatabaseService>();
        await databaseService.ClearAllAsync<IdentityDbContext>(_context);
        await MigrationAsync<Region>();
        await MigrationAsync<Group>();
        await MigrationAsync<Role>();
        await MigrationAsync<User>();
        await MigrationAsync<OAuthUser>();
        await MigrationAsync<RealNameInfo>();
        await MigrationAsync<UserRole>();
        await MigrationAsync<UserGroup>();
        await MigrationAsync<UserClaim>();
    }
    /// <summary>
    /// 认证数据库数据迁移
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    private async Task MigrationAsync<T>() where T : class
    {
        var mysqlDbContext = _serviceProvider.GetRequiredService<MySQLDbContext>();
        var data = await mysqlDbContext.Set<T>().AsNoTracking().ToListAsync();
        var total = data.Count;
        if (total != 0)
        {
            try
            {
                if (typeof(T) == typeof(RealNameInfo))
                {
                    foreach (var t in data)
                    {
                        if (t is RealNameInfo realNameInfo)
                        {
                            if (realNameInfo.CreatedOn is not null)
                            {
                                realNameInfo.CreatedOn = DateTime.SpecifyKind(realNameInfo.CreatedOn.Value, DateTimeKind.Utc);
                            }

                            if (realNameInfo.UpdatedOn is not null)
                            {
                                realNameInfo.UpdatedOn = DateTime.SpecifyKind(realNameInfo.UpdatedOn.Value, DateTimeKind.Utc);
                            }

                            if (realNameInfo.SendTime is not null)
                            {
                                realNameInfo.SendTime = DateTime.SpecifyKind(realNameInfo.SendTime.Value, DateTimeKind.Utc);
                            }

                            if (realNameInfo.ValidateTime is not null)
                            {
                                realNameInfo.ValidateTime = DateTime.SpecifyKind(realNameInfo.ValidateTime.Value, DateTimeKind.Utc);
                            }

                            if (realNameInfo.PhoneNumberValidateTime is not null)
                            {
                                realNameInfo.PhoneNumberValidateTime = DateTime.SpecifyKind(realNameInfo.PhoneNumberValidateTime.Value, DateTimeKind.Utc);
                            }

                            if (realNameInfo.IdCardValidateTime is not null)
                            {
                                realNameInfo.IdCardValidateTime = DateTime.SpecifyKind(realNameInfo.IdCardValidateTime.Value, DateTimeKind.Utc);
                            }

                            if (realNameInfo.FaceCompareValidateTime is not null)
                            {
                                realNameInfo.FaceCompareValidateTime = DateTime.SpecifyKind(realNameInfo.FaceCompareValidateTime.Value, DateTimeKind.Utc);
                            }

                            if (realNameInfo.FaceDetectionValidateTime is not null)
                            {
                                realNameInfo.FaceDetectionValidateTime = DateTime.SpecifyKind(realNameInfo.FaceDetectionValidateTime.Value, DateTimeKind.Utc);
                            }
                        }
                    }

                    await _context.AddRangeAsync(data);
                    await _context.SaveChangesAsync();
                }
                else
                {
                    await _context.InsertsAsync(data);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "迁移出错了!");
                throw ex;
            }

            data.Clear();
        }
    }
}